/**
 * Project 67th
 */


#include "TaskQueue.h"

/**
 * TaskQueue implementation
 */


/**
 * @param capa
 */
TaskQueue::TaskQueue(size_t capa) 
: _capacity(capa)
, _flag(true)
{

}

TaskQueue::~TaskQueue() {

}

/**
 * @param val
 * @return void
 */
void TaskQueue::push(ElemType val) {
    //1.先上锁
    /* _mtx.lock(); */
    unique_lock<mutex> ul(_mtx);

    //2.判满
    /* if(full()) */
    while(full()) //防止虚假唤醒
    {
        //2.1 如果TaskQueue是满的
        //就应该让生产者线程阻塞
        //注意：wait函数的传参必须是unique_lock
        _notFull.wait(ul);

        //底层原理是生产者线程先释放锁
        //等到被唤醒时再重新拿到锁
    }

    //2.2 如果TaskQueue不满
    //往TaskQueue中添加数据
    //并且唤醒消费者线程
    _que.push(val);
    _notEmpty.notify_one();

    //3.解锁
}

/**
 * @return int
 */
ElemType TaskQueue::pop() {
    unique_lock<mutex> ul(_mtx);

    //如果任务队列是空的，但是线程池并没有要退出
    //那么就应该阻塞
    //
    //如果任务队列是空的，但是线程池要退出
    //那么就不应该阻塞
    while(empty() && _flag)
    {
        _notEmpty.wait(ul);
    }

    //如果前面的循环结束，并且_flag = true
    //意味着任务队列中有任务
    //就可以取任务
    //
    //否则，代表这线程池要退出了
    //此时任务队列为空，无法取任务
    //就返回空指针
    if(_flag)
    {
        ElemType temp = _que.front();
        _que.pop();
        _notFull.notify_one();
        return temp;
    }
    else
    {
        return nullptr;
    }
}

void TaskQueue::wakeup()
{
    _flag = false;
    _notEmpty.notify_all();
}

/**
 * @return bool
 */
bool TaskQueue::full() {
    return _que.size() == _capacity;
}

/**
 * @return bool
 */
bool TaskQueue::empty() {
    return _que.size() == 0;
}


